package com.lzh.excel.exports.processor;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.write.builder.ExcelWriterBuilder;
import com.alibaba.excel.write.builder.ExcelWriterSheetBuilder;
import com.alibaba.excel.write.handler.WriteHandler;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.alibaba.excel.write.style.column.LongestMatchColumnWidthStyleStrategy;
import com.alibaba.excel.write.style.column.SimpleColumnWidthStyleStrategy;
import org.apache.commons.collections4.CollectionUtils;

import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;

/**
 * @author zhehen.lu
 * @date 2025/8/3 14:28
 */
public abstract class ExportAbstractProcessor<C, H, R> implements IExportProcessor<C, H, R> {
    private ThreadLocal<Class<H>> headClass = new ThreadLocal();

    public ExportAbstractProcessor() {
    }

    @Override
    public R export(OutputStream out, C condition) {
        this.invokeStart(out, condition);
        boolean exportFinish = false;
        ExcelWriter excelWriter = null;

        try {
            ExcelWriterBuilder write = EasyExcel.write(out);
            if (CollectionUtils.isNotEmpty(this.getAllWriteHandler())) {
                this.getAllWriteHandler().forEach((writeHandler) -> {
                    ExcelWriterBuilder var10000 = (ExcelWriterBuilder)write.registerWriteHandler(writeHandler);
                });
            }

            excelWriter = write.build();
            WriteSheet writeSheet = this.getWriteSheet(condition);
            excelWriter.write(new ArrayList(), writeSheet);
            this.invokeData(excelWriter, writeSheet, condition);
            exportFinish = true;
        } finally {
            if (excelWriter != null) {
                excelWriter.finish();
            }

            if (this.headClass.get() != null) {
                this.headClass.remove();
            }

        }

        return exportFinish ? this.invokeFinish(out, condition) : null;
    }

    @Override
    public R export(OutputStream out, C condition, Class<H> headClass) {
        this.headClass.set(headClass);
        return this.export(out, condition);
    }

    @Override
    public R export(String fileName, C condition) {
        this.invokeStart(fileName, condition);
        boolean exportFinish = false;
        ExcelWriter excelWriter = null;

        try {
            ExcelWriterBuilder write = EasyExcel.write(fileName);
            if (CollectionUtils.isNotEmpty(this.getAllWriteHandler())) {
                this.getAllWriteHandler().forEach((writeHandler) -> {
                    ExcelWriterBuilder var10000 = (ExcelWriterBuilder)write.registerWriteHandler(writeHandler);
                });
            }

            excelWriter = write.build();
            WriteSheet writeSheet = this.getWriteSheet(condition);
            excelWriter.write(new ArrayList(), writeSheet);
            this.invokeData(excelWriter, writeSheet, condition);
            exportFinish = true;
        } finally {
            if (excelWriter != null) {
                excelWriter.finish();
            }

            if (this.headClass.get() != null) {
                this.headClass.remove();
            }

        }

        return exportFinish ? this.invokeFinish(fileName, condition) : null;
    }

    @Override
    public R export(String fileName, C condition, Class<H> headClass) {
        this.headClass.set(headClass);
        return this.export(fileName, condition);
    }

    public List<List<String>> getDynamicHead(C condition) {
        return new ArrayList();
    }

    public List<String> getExcludeHead(C condition) {
        return new ArrayList();
    }

    public List<String> getIncludeHead(C condition) {
        return new ArrayList();
    }

    protected List<WriteHandler> getWriteHandler() {
        return new ArrayList();
    }

    protected Boolean isAutoMatchColumnWidth() {
        return false;
    }

    protected Integer getFixedColumWidth() {
        return null;
    }

    protected Integer getPageSize() {
        return 2000;
    }

    protected Boolean isAllBatchOnceDeal() {
        return false;
    }

    protected abstract String getSheetName(C var1);

    protected R invokeFinish(OutputStream out, C condition) {
        return null;
    }

    protected R invokeFinish(String fileName, C condition) {
        return null;
    }

    protected void invokeStart(OutputStream out, C condition) {
    }

    protected void invokeStart(String fileName, C condition) {
    }

    protected abstract List<H> invokeOnceTimeData(C var1, int var2, int var3);

    protected void invokeData(ExcelWriter excelWriter, WriteSheet writeSheet, C condition) {
        if (this.isAllBatchOnceDeal()) {
            List<H> data = this.invokeOnceTimeData(condition, 0, this.getPageSize());
            excelWriter.write(data, writeSheet);
        } else {
            int page = 1;

            while(true) {
                List<H> data = this.invokeOnceTimeData(condition, page, this.getPageSize());
                if (CollectionUtils.isEmpty(data)) {
                    break;
                }

                excelWriter.write(data, writeSheet);
                ++page;
            }
        }

    }

    private WriteSheet getWriteSheet(C condition) {
        if (CollectionUtils.isNotEmpty(this.getDynamicHead(condition))) {
            return ((ExcelWriterSheetBuilder)EasyExcel.writerSheet(this.getSheetName(condition)).head(this.getDynamicHead(condition))).build();
        } else if (CollectionUtils.isNotEmpty(this.getExcludeHead(condition))) {
            return ((ExcelWriterSheetBuilder)((ExcelWriterSheetBuilder)EasyExcel.writerSheet(this.getSheetName(condition)).head((Class)this.headClass.get())).excludeColumnFieldNames(this.getExcludeHead(condition))).build();
        } else {
            return CollectionUtils.isNotEmpty(this.getIncludeHead(condition)) ? ((ExcelWriterSheetBuilder)((ExcelWriterSheetBuilder)EasyExcel.writerSheet(this.getSheetName(condition)).head((Class)this.headClass.get())).includeColumnFieldNames(this.getIncludeHead(condition))).build() : ((ExcelWriterSheetBuilder)EasyExcel.writerSheet(this.getSheetName(condition)).head((Class)this.headClass.get())).build();
        }
    }

    private List<WriteHandler> getAllWriteHandler() {
        List<WriteHandler> writeHandlerList = new ArrayList();
        if (this.isAutoMatchColumnWidth()) {
            writeHandlerList.add(new LongestMatchColumnWidthStyleStrategy());
        }

        if (this.getFixedColumWidth() != null && this.getFixedColumWidth() > 0) {
            writeHandlerList.add(new SimpleColumnWidthStyleStrategy(this.getFixedColumWidth()));
        }

        if (CollectionUtils.isNotEmpty(this.getWriteHandler())) {
            writeHandlerList.addAll(this.getWriteHandler());
        }

        return writeHandlerList;
    }
}
